#ifndef FOREGROUNDEXTRACTOR_H
#define FOREGROUNDEXTRACTOR_H

#include <unistd.h>

#include <QImage>

#include "assert.h"
#include "opencv2/opencv.hpp"
#include "imagehelper.h"
#include "opencv2qt.h"


using namespace cv;

enum DISPLAY_TYPE
{
    SOURCE_DISPLAY_TYPE,
    LEARNED_IMAGE_DISPLAY_TYPE,
    AVERAGE_IMAGE_DISPLAY_TYPE,
    DELTA_IMAGE_DISPLAY_TYPE,
    MHI_DISPLAY_TYPE,
    MDI_DISPLAY_TYPE
};

enum POST_TRAITEMENT
{
    NONE_POST_TRAITEMENT,
    SOBEL_POST_TRAITEMENT,
    LAPLACE_POST_TRAITEMENT,
    NORMALMAP_POST_TRAITEMENT
};

enum DELTA_MODE
{
    DELTA_MODE_PREVIOUS_FRAME,
    DELTA_MODE_AVERAGE,
    DELTA_MODE_LEARNED_FRAME
};

/*!
  * \brief The ForegroundExtractor class contains a set of object and method to perform foreground extraction based on several image averaging.
  */
class ForegroundExtractor
{
    VideoCapture _capture;
    int _cols;
    int _rows;

    Mat _frame;
    Mat _result;
    Mat _reference;
    Mat _source;
    Mat _difference;
    Mat _runningAverage;
    int _runningAverageSize;
    Mat _movementHistoryImage;
    int _movementHistorySize;
    Mat _movementDensityImage;
    int _movementDensitySize;
    int _movementDensityThreshold;


    bool _blur;
    int _blurSize;
    bool _greyscale;
    bool _threshold;
    int _resultThreshold;

    int _pos;

public:

    DISPLAY_TYPE _displayType;
    DELTA_MODE _deltaMode;
    POST_TRAITEMENT _postTraitement;
    int _referenceSize;

    /*!
      * \brief ForegroundExtractor
      * \param rows
      * \param cols
      * \param averageWindowSize
      * \param color
      */
    ForegroundExtractor(DISPLAY_TYPE displayType = MDI_DISPLAY_TYPE,
                        DELTA_MODE deltaMode = DELTA_MODE_LEARNED_FRAME,
                        POST_TRAITEMENT postTraitement = NONE_POST_TRAITEMENT,
                        int referenceSize = 32,
                        int runningAverageSize = 32,
                        int movementHistorySize = 32,
                        int movementDensitySize = 32,
                        int movementDensityThreshold = 5,
                        int resultThreshold = 5,
                        bool greyscale = true);

    ~ForegroundExtractor();

    /*! \brief cols return the columns count of handled image*/
    int cols() const;

    /*! \brief rows return the rows count of handled image*/
    int rows() const;

    /*!
      * \brief update add a frame to a *running average image*.
      * The *running average image* is a *16 bit-depth* image wich can contains an aproximation of the average of up to 256 *8bit-depth* image.
      * The size of the running average *window size* define the number of frame to add up into the *running average image*.
      * When the number of frame added up to the *running average image* reach the running average *window size*.
      * The aglorithm substract the pixel value divide be the *window size* : so it take the 8-bit average from 16-bit running average image.
      * \param frame a frame of size (`ForegroundExtractor::rows()`,`ForegroundExtractor::cols()`)
      */
    void update();
    void updateDelta(Mat& frame);
    void updateRunningAverage(Mat& frame);
    void updateMovementHisotryImage(Mat& frame);
    void updateMovementDensityImage(Mat& frame);

    void delta(Mat& output) const;
    void runningAverage(Mat& output) const;
    void movementHistoryImage(Mat& output) const;
    void movementDensityImage(Mat& output) const;
    void result(Mat &output) const;

    void sobel(Mat &value, int sigma, int threshold) const;
    void laplacian(Mat &value) const;
    void normalMap(Mat &value, double scale) const;

    void learn();
    void clear();

    void setBlur(bool value);
    void setThreshold(bool value);
    void setThresholdValue(int value);

    QImage getFrame();


};

#endif // FOREGROUNDEXTRACTOR_H

//    Mat _RAI;
//    Mat _MHI;

//    /*!
//      * \brief difference return 8bit image where each pixel represent the absolute intensity difference between the two image at this pixel.
//      * Be reference a frame a matrix \f$I_{ref}\f$ and frame a matrix \f$I\f$. The retruned output is the matrix
//      * \f$\Delta I(x,y)=||I(x,y)−I_{ref}(x,y)||,\forall(x,y)\f$
//      * \param reference image of reference. It can be a simple previously captured frame or a statisctical modelisation of the background.
//      * \param frame image used to compute difference with reference image.
//      * \param outpout image containing the intensity difference between both images.
//      */
//    void difference(const Mat& reference, const Mat& frame, Mat& output) const;

//    /*!
//      * \brief addFrame threshold the difference `frame` and add to the mouvement history image `MHI`.
//      * The difference frame is binary thresholded the `_threshold` parameter value.
//      * The resulting binary image is added to `_MHI` at position `_pos % 32` (so if an older frame already exists at this position it's crush).
//      * `_pos` is incremented by one.
//      * \param frame a frame of size (`ForegroundExtractor::rows()`,`ForegroundExtractor::cols()`). It should be a difference frame, computed between two image with `ForegroundExtractor::difference` method.
//      */
//    void addDifferenceFrame(const Mat& frame, int size);

//    /*!
//      * \brief differenceRunningAverage
//      * \param output
//      */
//    void differenceRunningAverage(Mat &output) const;

///*!
//  * \brief runningAverageImage
//  * \param output
//  */
//void runningAverageImage(Mat& output) const;
